Socket
Socket
Sign inDemoInstall

@data-client/endpoint

Package Overview
Dependencies
Maintainers
0
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@data-client/endpoint

Declarative Network Interface Definitions


Version published
Weekly downloads
1.1K
decreased by-20.83%
Maintainers
0
Weekly downloads
 
Created
Source

TypeScript Standard Endpoints

CircleCI Coverage Status npm downloads bundle size npm version PRs Welcome

Declarative, strongly typed, reusable network definitions for networking libraries.

Usage

1) Take any class and async functions

export class Todo {
  id = 0;
  userId = 0;
  title = '';
  completed = false;
}

export const getTodo = (id: string) =>
  fetch(`https://jsonplaceholder.typicode.com/todos/${id}`).then(res => res.json());

export const getTodoList = () =>
  fetch('https://jsonplaceholder.typicode.com/todos').then(res => res.json());

export const updateTodo = (id: string, body: Partial<Todo>) =>
  fetch(`https://jsonplaceholder.typicode.com/todos/${id}`, {
    method: 'PUT',
    body: JSON.stringify(body),
  }).then(res => res.json());

2) Turn them into Resources

import { schema, Endpoint } from '@data-client/endpoint';
import { Todo, getTodoList, updateTodo } from './existing';

export const TodoEntity = schema.Entity(Todo, { key: 'Todo' });

export const TodoResource = {
  get: new Endpoint(getTodo, {
    schema: TodoEntity,
  }),
  getList: new Endpoint(getTodoList, {
    schema: [TodoEntity],
  }),
  update: new Endpoint(updateTodo, {
    schema: TodoEntity,
    sideEffect: true,
  }),
};

3) Reuse with different hooks

import { useSuspense, useController } from '@data-client/react';

function TodoEdit() {
  const todo = useSuspense(TodoResource.get, '5');
  const ctrl = useController();
  const updateTodo = (data) => ctrl.fetch(TodoResource.update, id, data);

  return <TodoForm todo={todo} onSubmit={updateTodo} />
}

4) Or call directly in node

const todo = await TodoResource.get('5')
console.log(todo);

Why

There is a distinction between

  • What are networking API is
    • How to make a request, expected response fields, etc.
  • How it is used
    • Binding data, polling, triggering imperative fetch, etc.

Thus, there are many benefits to creating a distinct seperation of concerns between these two concepts.

With TypeScript Standard Endpoints, we define a standard for declaring in TypeScript the definition of a networking API.

  • Allows API authors to publish npm packages containing their API interfaces
  • Definitions can be consumed by any supporting library, allowing easy consumption across libraries like Vue, React, Angular
  • Writing codegen pipelines becomes much easier as the output is minimal
  • Product developers can use the definitions in a multitude of contexts where behaviors vary
  • Product developers can easily share code across platforms with distinct behaviors needs like React Native and React Web

What's in an Endpoint

  • A function that resolves the results
  • A function to uniquely store those results
  • Optional: information about how to store the data in a normalized cache
  • Optional: whether the request could have side effects - to prevent repeat calls

API

@data-client/endpoint defines a standard interface

interface EndpointInterface {
    (params?: any, body?: any): Promise<any>;
    key(parmas?: any): string;
    schema?: Readonly<S>;
    sideEffects?: true;
    // other optionals like 'optimistic'
}

as well as a helper class to make construction easier.

class Endpoint<F extends () => Promise<any>> {
  constructor(fetchFunction: F, options: EndpointOptions);

  key(...args: Parameters<F>): string;

  readonly sideEffect?: true;

  readonly schema?: Schema;

  fetch: F;

  extend(options: EndpointOptions): Endpoint;
}

export interface EndpointOptions extends EndpointExtraOptions {
  key?: (params: any) => string;
  sideEffect?: true | undefined;
  schema?: Schema;
}

EndpointOptions

key: (params) => string

Serializes the parameters. This is used to build a lookup key in global stores.

Default:

`${this.fetch.name} ${JSON.stringify(params)}`

sideEffect: true | undefined

Disallows usage in hooks like useSuspense() since they might call fetch an unpredictable number of times. Use this for APIs with mutation side-effects like update, create, deletes.

Defaults to undefined meaning no side effects.

schema: Schema

Declarative definition of where Entities appear in the fetch response.

Not providing this option means no entities will be extracted.

import { Entity } from '@data-client/normalizr';
import { Endpoint } from '@data-client/endpoint';

class User extends Entity {
  readonly id: string = '';
  readonly username: string = '';

  pk() { return this.id;}
}

const UserDetail = new Endpoint(
    ({ id }) ⇒ fetch(`/users/${id}`),
    { schema: User }
);

Endpoint

extend(EndpointOptions): Endpoint

Can be used to further customize the endpoint definition

const UserDetail = new Endpoint(({ id }) ⇒ fetch(`/users/${id}`));


const UserDetailNormalized = UserDetail.extend({ schema: User });

Index

import { Entity } from '@data-client/normalizr';
import { Index } from '@data-client/endpoint';

class User extends Entity {
  readonly id: string = '';
  readonly username: string = '';

  pk() { return this.id;}
  static indexes = ['username'] as const;
}

const bob = useQuery(User, { username: 'bob' });

// @ts-expect-error Indexes don't fetch, they just retrieve already existing data
const bob = useSuspense(UserIndex, { username: 'bob' });

API

Keywords

FAQs

Package last updated on 21 Jun 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc